/*
 * Matthew Cramer, Jesse Martinez, Marc Mendoza 
 * CSE 325 Lab 1
 * File: QueueManager.c
 * Description: Manager that handles calls to the Queue.  This is called from
 *              the testing interface to perform the functions to the stack.
 *
 */

#define NUM_REGS 3
#define MAX_PROCESSES 20
#define NULL 0

/*
* Declare variables to use at indexes
* lastIndex is the Head of the Stack: -1 indicates Stack is empty
*/
int lastIndex = -1; 
int regsIndex = NUM_REGS;
int processIndex = MAX_PROCESSES;

/*
 * Struct for Queue
 */
struct process_control_block {
    int pid;   //Process ID
    int psw;   //Program Status Word
    int pageTable;   //Page Table Info
    int prevIndex;   //Pointer to Previous Index in List
    int nextIndex;   //Pointer to Next Index in List
    int regs[3];  //Define register array to hold register values
}process[20];   //Declare array of structs = Stack

/*
 * Declare functions
 */
void Enqueue(int, int, int, int, int, int);
int Dequeue();
int Delete(int);
void list(int *);
int QueueSize();

/*
 * List: Receives the address of an array to place PIDs of processes in the Queue
 */
void list(int* temp)
{
    int i;
    for(i=0; i<lastIndex+1; i++)
    {
        temp[i] = process[i].pid;
    }
}

/*
 * QueueSize: Returns the size of the current Queue
 */
int QueueSize()
{
    return lastIndex+1;
}


/*
 * Enqueue: Receives information from Testing Interface to put onto stack
 */
void Enqueue(int processNumber, int psw, int pageTable, int reg0, int reg1, int reg2)
{
	/*
	 * Store values from testing interface onto the stack
	 */
    if(lastIndex >= 0)
    {
        int i;
        
        for(i=lastIndex; i>=0; i--)
        {
            /*
             * Moves head struct to next index
             */
            if(i==lastIndex)
            {
                process[lastIndex+1] = process[i];
                process[i+1].prevIndex=i;
                process[i+1].nextIndex=-1;
            }
            /*
             * Moves the rest of the elements down in the queue
             */
            else 
            {
                process[process[i].nextIndex] = process[i];
                process[i+1].prevIndex=i;
                process[i+1].nextIndex=i+2;
            }            
        }
    }
	
    /*
     * Stores new process at tail of Queue
     */
    process[0].pid = processNumber;
    process[0].psw = psw;
    process[0].pageTable = pageTable;
    process[0].regs[0] = reg0;
    process[0].regs[1] = reg1;
    process[0].regs[2] = reg2;
    process[0].prevIndex = -1;
    process[0].nextIndex = 1;
    lastIndex++;
}

/*
 * Dequeue: returns the PID at head of Queue and Deletes it, -1 if no elements
 */
int Dequeue()
{
	int value;// gets the process id from the queue
	if(lastIndex != -1)
	{
        value = process[lastIndex].pid;
		//Below sets everything to Null so that space is able to be used again
        process[lastIndex].pid = 0;
        process[lastIndex].psw = 0;
        process[lastIndex].regs[0]=0;
        process[lastIndex].regs[1]=0;
        process[lastIndex].regs[2]=0;
        lastIndex--; //we decrement last index to move up the pointer to show the next filled spot inside the queue
	}
	else
	{
		value = -1;//tells the test interface that there is nothing in the queue to dequeue 
	}
	return value;
	
}

/*Delete: Receives the pid of the process to be deleted.
*		Returns the pid when delete is a successful and -2 if pid is not found.
*/
int Delete(int processNumber)
{
	int i, j; //for counter variable

	//iterates through the list until the process id is found
	for(i=lastIndex; i>=0; i--)
	{
		if(process[i].pid == processNumber)
		{
			//if the process is the header
			if(i == lastIndex)
			{
				process[i-1].nextIndex = i;
				
				//previous head is nulled
				process[i].pid = NULL;
				process[i].psw = NULL;
				process[i].pageTable = NULL;
				process[i].regs[0] = NULL;
				process[i].regs[1] = NULL;
				process[i].regs[2] = NULL;
				process[i].prevIndex = NULL;
				process[i].nextIndex = NULL;
			}
			
			//everything is moved up the array and the lastIndex is nulled
			else
			{
				for(i; i<lastIndex; i++)
				{
					//the process at i+1 is moved to i
					process[i].pid = process[i+1].pid;
					process[i].psw = process[i+1].psw;
					process[i].pageTable = process[i+1].pageTable;
					process[i].regs[0] = process[i+1].regs[0];
					process[i].regs[1] = process[i+1].regs[0];
					process[i].regs[2] = process[i+1].regs[0];
					process[i].prevIndex = i-1;
					process[i].nextIndex = i+1;
				}
				
				//the previous position of the head is nulled
				process[i].nextIndex = -1;
				process[i+1].pid = NULL;
				process[i+1].psw = NULL;
				process[i+1].pageTable = NULL;
				process[i+1].regs[0] = NULL;
				process[i+1].regs[1] = NULL;
				process[i+1].regs[2] = NULL;
				process[i+1].prevIndex = NULL;
				process[i+1].nextIndex = i++;
			}
			
			//lastIndex is updated to new position of the head
			lastIndex--;
			return processNumber;
		}
	}
	
	//returns no existing process error
	return -2;
}

/*
 * Clear: Clears the stack of all structs
 */
void clear()
{
	int x=0;
	for(x=0; x<20; x++)
	{
		process[x].pid = 0;
		process[x].psw = 0;
		process[x].regs[0]=0;
		process[x].regs[1]=0;
		process[x].regs[2]=0;
	}
	lastIndex = -1;
}
